home *** CD-ROM | disk | FTP | other *** search
- /* color mapping with splitted color palette */
- #ifndef MAPPER_H
- #define MAPPER_H
-
- #include <mem.h>
- #include <math.h>
- #include <alloc.h>
- #include "common.h"
- #include "graph.h"
- #include "mapper.h"
-
- color_mapper::color_mapper(int colors_,int width_,BGRpalette colormap) {
- int i;
-
- initialized = TRUE;
- on_odd_row = FALSE;
- actual_number_of_colors = colors_;
- memmove(my_colormap,colormap,actual_number_of_colors*sizeof(colortype));
- width = width_;
- for (i = 0; i < 3 ; i++) {
- error[i] = NULL;
- next_line_error[i] = NULL;
- }
- }
-
- color_mapper::~color_mapper() {
- int i;
-
- for (i = 0; i < 3 ; i++) {
- if (error[i] != NULL) delete error[i];
- if (next_line_error[i] != NULL) delete next_line_error[i];
- }
-
- }
-
- color_mapper::prepare_dithering() {
- int i;
-
- for (i = 0; i < 3; i++) {
- error[i] = new int[width + 2];
- next_line_error[i] = new int[width + 2];
- if ((error[i] == NULL) || (next_line_error[i] == NULL)) return(-1);
- memset(error[i],0,sizeof(int)*(width + 2));
- }
- return(1);
- }
-
- // ================== splitted colors
-
- void color_mapper_splitted::init(int width_,BYTE *color_values[3],
- BYTE color_num_[3]){
- int i,j, col, r,g,b ;
-
- initialized = FALSE;
- width = width_;
- actual_number_of_colors = 1;
- for (i = 0; i < 3; i++) {
- color_num[i] = color_num_[i];
- actual_number_of_colors *= color_num[i];
- }
- if (actual_number_of_colors > 256) return;
- col = 0;
- for (r = 0; r < color_num[0]; r++)
- for (g = 0; g < color_num[1]; g++)
- for (b = 0; b < color_num[2]; b++) {
- my_colormap[col].r = color_values[0][r];
- my_colormap[col].g = color_values[1][g];
- my_colormap[col++].b = color_values[2][b];
- }
-
- if (prepare_dithering() < 0) return;
- for (i = 0; i < 3; i++) prepare_table(color_values[i], i);
- initialized = TRUE;
- }
-
- void color_mapper_splitted::prepare_table(BYTE *values,int color_index) {
- int i,j, thres, prev_thres, val, num, multipl;
- BYTE *table,*value_tab;
-
- convert_table0[color_index] = new BYTE[3*256+1];
- convert_table[color_index] = &convert_table0[color_index][256];
-
- table = convert_table[color_index];
- num = color_num[color_index];
- prev_thres = -257;
- for (i = 0; i < num-1; i++) {
- thres = (values[i] + values[i+1]) / 2;
- for (j = prev_thres+1; j <= thres; j++) table[j] = i;
- prev_thres = thres;
- }
- for (j = prev_thres+1; j <= 2*256; j++) table[j] = num -1;
- value_tab = new BYTE[num];
- for (i = 0; i < num; i++) value_tab[i] = values[i];
- value_table[color_index] = value_tab;
- max_color_value = max(max_color_value,value_tab[num-1]);
- }
-
-
-
- int color_mapper_splitted::select_colors_num(int max_colors) {
- /* based on procedure from Independent JPEG Group's software */
- /* Determine allocation of desired colors to components, */
- /* and fill in color_num[] array to indicate choice. */
-
- int nc,total_colors, iroot, i;
- long temp;
- BOOL changed;
-
- if ((max_colors < 8) || (max_colors > 256)) return(-1);
-
- /* We can allocate at least the nc'th root of max_colors per component. */
- /* Compute floor(nc'th root of max_colors). */
-
- nc = 3;
- iroot = 1;
- do {
- iroot++;
- temp = iroot; /* set temp = iroot ** nc */
- for (i = 1; i < nc; i++)
- temp *= iroot;
- } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */
- iroot--; /* now iroot = floor(root) */
-
- /* We provide a special policy for quantizing in RGB space.
- * If 256 colors are requested, we allocate 8 red, 8 green, 4 blue levels;
- * this corresponds to the common 3/3/2-bit scheme. For other totals,
- * the counts are set so that the number of colors allocated to each
- * component are roughly in the proportion R 3, G 4, B 2.
- * For low color counts, it's easier to hardwire the optimal choices
- * than try to tweak the algorithm to generate them.
- */
- if (max_colors == 256) {
- color_num[0] = 8; color_num[1] = 8; color_num[2] = 4;
- return 1;
- }
-
- if (max_colors < 12) {
- /* Fixed mapping for 8 colors */
- color_num[0] = color_num[1] = color_num[2] = 2;
- } else if (max_colors < 18) {
- /* Fixed mapping for 12 colors */
- color_num[0] = 2; color_num[1] = 3; color_num[2] = 2;
- } else if (max_colors < 36) {
- /* Fixed mapping for 18 colors */
- color_num[0] = 3; color_num[1] = 3; color_num[2] = 2;
- } else {
- /* these weights are readily derived with a little algebra */
- color_num[0] = (iroot * 266) >> 8; /* R weight is 1.0400 */
- color_num[1] = (iroot * 355) >> 8; /* G weight is 1.3867 */
- color_num[2] = (iroot * 177) >> 8; /* B weight is 0.6934 */
- }
- total_colors = color_num[0] * color_num[1] * color_num[2];
- /* The above computation produces "floor" values, so we may be able to
- * increment the count for one or more components without exceeding
- * max_colors. We try in the order B, G, R.
- */
- do {
- changed = FALSE;
- for (i = 2; i >= 0; i--) {
- /* calculate new total_colors if color_num[i] is incremented */
- temp = total_colors / color_num[i];
- temp *= color_num[i]+1; /* done in long arith to avoid oflo */
- if (temp <= (long) max_colors) {
- color_num[i]++; /* OK, apply the increment */
- total_colors = (int) temp;
- changed = TRUE;
- }
- }
- } while (changed); /* loop until no increment is possible */
-
- return(1);
- }
-
- color_mapper_splitted::color_mapper_splitted(int width_,BYTE *color_values[3],
- BYTE color_num_[3]){
- max_color_value = 0;
- color_mapper_splitted::init(width_,color_values,color_num_);
- }
- // short cut
- color_mapper_splitted::color_mapper_splitted(int colors_,int width_,int max_color_value_) {
- int i,j,c_num;
- BYTE val[3][10];
- BYTE *vp[3];
- max_color_value = max_color_value_;
- initialized = FALSE;
- if ((max_color_value > 255) || (select_colors_num(colors_) < 0)) return;
- for (i = 0; i < 3; i++) {
- val[i][0] = 0;
- c_num = color_num[i];
- val[i][c_num-1] = max_color_value;
- for (j = 1; j < c_num-1; j++)
- val[i][j] = (max_color_value*j) / (c_num - 1);
- }
- for (i = 0; i < 3; i++) vp[i] = val[i];
- color_mapper_splitted::init(width_,vp,color_num);
- initialized = TRUE;
- }
-
-
- color_mapper_splitted::~color_mapper_splitted() {
- int i;
- for (i = 0; i < 3; i++) {
- if (convert_table[i] != NULL) delete convert_table0[i];
- if (value_table[i] != NULL) delete value_table[i];
- }
- }
-
-
- void color_mapper_splitted:: process_line(BYTE *R, BYTE *G, BYTE *B, BYTE *out_line) {
- memset(out_line,0,width); // initialize output to process componentes separately
- process_one_color(R, out_line, 0);
- process_one_color(G, out_line, 1);
- process_one_color(B, out_line, 2);
- on_odd_row = (on_odd_row ? FALSE : TRUE);
- }
-
- void color_mapper_splitted::process_one_color(BYTE *in, BYTE *out_line, int col_ind) {
- register int val;
- int two_val,multipl,i;
- register int *thisrowerr, *nextrowerr;
- int *swp;
- BYTE *convert_tab, *value_tab;
- register int pixcode;
- int column;
- int dir; /* 1 for left-to-right, -1 for right-to-left */
-
- thisrowerr = error[col_ind] + 1;
- nextrowerr = next_line_error[col_ind] + width;
- convert_tab = convert_table[col_ind];
- value_tab = value_table[col_ind];
-
- if (on_odd_row) {
- /* work right to left in this row */
- dir = -1;
- in += width-1;
- out_line += width-1;
- } else {
- /* work left to right in this row */
- dir = 1;
- }
-
- multipl = 1;
- for (i = col_ind+1; i < 3; i++) multipl *=color_num[i];
- *nextrowerr = 0; /* need only initialize this one entry */
-
- for (column = width; column > 0; column--) {
- /* Get accumulated error for this component, round to integer.
- * (error was scaled in 16 times)
- * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
- * for either sign of the error value.
- */
- val = *in + ((*thisrowerr + 8) >> 4);
- /* Compute pixel value + error compensation,
- * Note max error value is +- MAXJSAMPLE.
- */
-
- pixcode = convert_tab[val]; // partial color index
-
- /* Select output value, accumulate into output code for this pixel */
-
- if (col_ind == 0) *out_line = pixcode;
- else *out_line += multipl*pixcode;
-
- /* Compute actual representation error at this pixel */
- /* Note: we can do this even though we don't yet have the final */
- /* value of pixcode, because the colormap is orthogonal. */
- val -= value_tab[pixcode];
- /* Propagate error to (same component of) adjacent pixels */
- /* Remember that nextrowerr entries are in reverse order! */
- two_val = val << 1; // *2
- nextrowerr[-1] = val; /* not +=, since not initialized yet */
- val += two_val; /* form error * 3 */
- nextrowerr[ 1] += val;
- val += two_val; /* form error * 5 */
- nextrowerr[ 0] += val;
- val += two_val; /* form error * 7 */
- thisrowerr[ 1] += val;
- in += dir; /* advance input ptr to next column */
- out_line += dir; /* advance output ptr to next column */
- thisrowerr++; /* cur-row error ptr advances to right */
- nextrowerr--; /* next-row error ptr advances to left */
- }
- swp = error[col_ind];
- error[col_ind] = next_line_error[col_ind]; // swap pointers for future
- next_line_error[col_ind] = swp;
- }
-
-
- color_mapper_gray::color_mapper_gray(int colors_,int width_,int max_color_value_) {
- int i,j, col;
- BYTE val[256];
-
- initialized = FALSE;
- max_color_value = max_color_value_;
- if ((max_color_value > 255) || (colors_ > 255)) return;
-
- width = width_;
- actual_number_of_colors = colors_;
-
- color_num[0] = colors_;
- color_num[1] = 1; color_num[2] = 1; // it's important!
- val[0] = 0;
- val[colors_-1] = max_color_value;
- for (j = 1; j < colors_-1; j++)
- val[j] = (max_color_value*j) / (colors_ - 1);
-
- col = 0;
- for (col = 0; col < colors_; col++) {
- my_colormap[col].r = val[col];
- my_colormap[col].g = val[col];
- my_colormap[col].b = val[col];
- }
-
-
- error[0] = new int[width + 2];
- next_line_error[0] = new int[width + 2];
- if ((error[0] == NULL) || (next_line_error[0] == NULL)) return;
- memset(error[0],0,sizeof(int)*(width + 2));
-
- error[1] = error[2] = NULL;
- next_line_error[1] = next_line_error[2] = NULL;
- value_table[1] = value_table[2] = NULL;
- convert_table0[1] = convert_table0[2] = NULL;
-
- prepare_table(val, 0);
- initialized = TRUE;
- }
-
- void color_mapper_gray:: process_line(BYTE *source,BYTE *out_line) {
- memset(out_line,0,width); // initialize output to process componentes separately
- process_one_color(source, out_line, 0);
- on_odd_row = (on_odd_row ? FALSE : TRUE);
-
- }
-
- #endif
-